﻿using System;
using System.Collections.Generic;
using System.Linq;
using LumenLiquid.Database;
using LumenLiquid.Database.Entities.Settings;
using LumenLiquid.Debug;
using Microsoft.Xna.Framework;
using NHibernate;
using DebugLevel = LumenLiquid.Debug.DebugHandler.EDebugLevel;

namespace LumenLiquid.InGame
{
    public struct SIdInfo
    {
        public int Id { get; private set; }
        public string Param1 { get; private set; }
        public string Param2 { get; private set; }
        public string Name { get; private set; }


        public SIdInfo(int id = -1, string name = "")
            : this()
        {
            Id = id;
            Name = name;
        }

        public SIdInfo(int id, string name, string param1)
            : this()
        {
            Id = id;
            Param1 = param1;
            Name = name;
        }

        public SIdInfo(int id, string name, string param1, string param2)
            : this()
        {
            Id = id;
            Param1 = param1;
            Name = name;
            Param2 = param2;
        }
    }

    class MainGame
    {
        #region Properties
        public static MainGame Instance { get; private set; }
        public string World { get; private set; }
        public Matrix Camera { get; private set; }
        public Matrix Projection { get; private set; }
        public Vector3 CameraPosition { get; private set; }
        #endregion

        private ISessionFactory _settingsDatabase;
        private Properties _properties;
        private IEnumerable<SavegameInfo> _savegames;

        private IEnumerable<WorldInfo> _worlds;
        private World _world;

        public MainGame(Properties properties, ISessionFactory settingsDatabase)
        {
            DebugHandler.Log("Initializing game instance...", DebugLevel.Code);

            Instance = this;
            _properties = properties;
            _settingsDatabase = settingsDatabase;


            IStatelessSession session = _settingsDatabase.OpenStatelessSession();
            _savegames = DatabaseInteraction.ReadAllObjects<SavegameInfo>(session);

            _worlds = DatabaseInteraction.ReadAllObjects<WorldInfo>(session);

            session.Close();

            //Initialize render variables
            CameraPosition = new Vector3(0, 10, -60);
            Camera = Matrix.CreateLookAt(CameraPosition, new Vector3(0, 0, 0), Vector3.Up);
            Projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.ToRadians(45), Main.Instance.Screensize.X / Main.Instance.Screensize.Y, 0.1f, 1000f);

            //Todo: replace with loading routine
            if (LoadWorld(Convert.ToInt32(_properties[(int)Main.EProperties.StartupWorld])) == false)
                return;

            DebugHandler.Log("Game initialized sucessfully.", DebugLevel.Code);
        }

        #region XNA Properties
        public void Draw(GameTime gameTime)
        {
            _world.Draw(gameTime);
        }

        public void Update(GameTime gameTime)
        {
            _world.Update(gameTime);
        }
        #endregion

        /// <summary>
        /// Returns a list containing all registered worlds and their location
        /// </summary>
        /// <returns></returns>
        /// <Remarks>Id stores the id of the world, name the translation and Param1 the folder</Remarks>
        public List<SIdInfo> GetWorlds()
        {
            return _worlds.Select(world => new SIdInfo(world.Id, Main.Instance.Translation(world.Translation), world.Folder)).ToList();
        }

        private bool LoadWorld(int id)
        {
            if (_world != null)
                _world.ShutdownTransactions();

            string oldWorld = World;

            World = GetWorlds().FirstOrDefault(m => m.Id.Equals(id)).Param1;

            _world = new World();
            if (_world.Init(id) == false)
            {
                DebugHandler.Log("Error initializing world...", DebugLevel.Error);
                Main.Instance.EndGame();
            }

            Main.Instance.Texturemanager.UnloadGroup(oldWorld);

            return true;
        }
    }
}
